package edu.neu.cs6515.gui;

import java.awt.Dimension;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;

import javax.swing.JPanel;

import lombok.Getter;
import edu.neu.cs6515.board.Hexagon;
import edu.neu.cs6515.board.HexagonBoard;

/**
 * Class to render edu.neu.cs6515.xml.Board
 */
public final class BoardRenderer extends JPanel {

    private static final long serialVersionUID = 1L;

    @Getter
    private Map<Hexagon, CellRenderer> hexToCells = new LinkedHashMap<Hexagon, CellRenderer>();

    private HexagonBoard board;

    /**
     * constructor of BoardRenderer
     * 
     */
    public BoardRenderer() {
        this.setLayout(null);
    }

    /**
     * create Cell for each Hexagon
     */
    private void initializeHexToCells() {
        this.removeAll();
        Hexagon currentHex = board.getHexagonAt(0, 0);
        int centerX = (int) this.getPreferredSize().getWidth() / 2
                - CellRenderer.RADIUS;
        int centerY = (int) this.getPreferredSize().getHeight() / 2
                - CellRenderer.RADIUS;
        hexToCells.put(currentHex, createCell(currentHex, centerX, centerY));
        while (hexToCells.keySet().size() < board.getHexagons().keySet().size()) {
            Set<Hexagon> hexToBeVisited = new HashSet<Hexagon>(
                    hexToCells.keySet());
            createCellsAndAddToHexToCells(hexToBeVisited);
        }
    }

    /**
     * create neighboring Cells for hexagons in hexHaveCell
     * 
     * @param hexToBeVisited
     *            hexagons already have cells
     */
    private void createCellsAndAddToHexToCells(final Set<Hexagon> hexToBeVisited) {
        CellRenderer currentCell;
        for (Hexagon hexagon : hexToBeVisited) {
            currentCell = hexToCells.get(hexagon);
            createCellAndPutInMap(currentCell, hexagon.getTop(), 0,
                    -CellRenderer.DIAMETER);
            createCellAndPutInMap(currentCell, hexagon.getTopRight(),
                    CellRenderer.DIAMETER, -CellRenderer.DIAMETER / 2);
            createCellAndPutInMap(currentCell, hexagon.getBottomRight(),
                    CellRenderer.DIAMETER, CellRenderer.DIAMETER / 2);
            createCellAndPutInMap(currentCell, hexagon.getBottom(), 0,
                    CellRenderer.DIAMETER);
            createCellAndPutInMap(currentCell, hexagon.getBottomLeft(),
                    -CellRenderer.DIAMETER, CellRenderer.DIAMETER / 2);
            createCellAndPutInMap(currentCell, hexagon.getTopLeft(),
                    -CellRenderer.DIAMETER, -CellRenderer.DIAMETER / 2);
        }
    }

    /**
     * create Cell for neighborHex by adding deltaX and deltaY to currentCell
     * 
     * @param currentCell
     *            cell known coordinates
     * @param neighborHex
     *            Hexagon to create cell for
     * @param deltaX
     *            delta for x coordinate
     * @param deltaY
     *            delta for y coordinate
     */
    private void createCellAndPutInMap(final CellRenderer currentCell,
            final Hexagon neighborHex, final int deltaX, final int deltaY) {
        if (neighborHex != null && !hexToCells.keySet().contains(neighborHex)) {
            CellRenderer neighborCell = createCell(neighborHex,
                    currentCell.getX() + deltaX, currentCell.getY() + deltaY);
            hexToCells.put(neighborHex, neighborCell);
        }
    }

    /**
     * @param hex hexagon to creat cell for
     * @param x x coordinate of the cell
     * @param y y coordinate
     * @return the cell that has x,y as coordinate, representing hex
     */
    private CellRenderer createCell(final Hexagon hex, final int x, final int y) {
        CellRenderer cell = new CellRenderer(hex.getDistance(), hex.getAngle(),
                hex.getColor());
        this.add(cell);
        cell.setLocation(x, y);
        return cell;
    }

    /**
     * update the BoardRenderer to render given board
     * @param board to be rendered
     */
    public void update(final HexagonBoard board) {
        this.board = board;
        hexToCells = new LinkedHashMap<Hexagon, CellRenderer>();
        this.setPreferredSize(new Dimension((board.getNbrOfPlayers() * 2 + 7)
                * CellRenderer.DIAMETER, (board.getNbrOfPlayers() * 2 + 7)
                * CellRenderer.DIAMETER));
        initializeHexToCells();
    }
}
